/* eslint-disable @typescript-eslint/no-unused-vars */ //
import type { DependencyList, Dispatch, EffectCallback, SetStateAction } from 'react';
import { message } from 'antd';
import { history, useIntl } from 'umi';
import serviceUtils from '@/services/serviceUtils';
import type { Task, Project, Data } from '@/services/web';
import {
  ProjectApi,
  TaskApi,
  DataApi,
  AnnotationApi,
  LabelApi,
  ManageApi,
  Configuration,
  SampleApi,
  RpcApi,
} from '@/services/web';
import { HistoryUtils } from '@/services/history';
import { IntlInitJsx } from '@/components/PPIntl';
import type { ToolType, Annotation, Label } from '@/models/';
import { ModelApi } from '@/services/ml';
import type { InlineObject1, Model } from '@/services/ml/models';
import type { MessageApi } from 'antd/lib/message';
import { reject } from 'lodash';

const baseUrl = localStorage.getItem('basePath');
// const localstorage_list = [];
const localStorageListString = localStorage.getItem('data_list');
let parsedList: any[] | null = null;
// const dataIndex = 0;
console.log('baseUrl', baseUrl);
const config = new Configuration(baseUrl ? { basePath: baseUrl } : undefined);
// const STORAGE_KEY = 'taskCache'; // 缓存键名
const STORAGE_KEY = localStorage.getItem('username');
const rpcApi = new RpcApi(config);
const projectApi = new ProjectApi(config);
const taskApi = new TaskApi(config);
const dataApi = new DataApi(config);
const annotationApi = new AnnotationApi(config);
const labelApi = new LabelApi(config);
let currIdx_origin: number;
const dbName = 'myDatabase';
const storeName = 'myStore';
let db: IDBDatabase | null = null;

function openDB(): Promise<IDBDatabase> {
  return new Promise((resolve, reject) => {
    const request = indexedDB.open(dbName, 1);
    request.onerror = () => {
      reject(request.error);
    };
    request.onsuccess = (event) => {
      db = request.result;
      resolve(db);
    };
    request.onupgradeneeded = function (event) {
      const db = event.target.result;
      if (!db.objectStoreNames.contains(storeName)) {
        const store = db.createObjectStore(storeName, { keyPath: 'id' });
        store.createIndex('usernameIndex', 'username', { unique: false });
      }
    };
  });
}
function closeDB() {
  if (db) {
    db.close();
    db = null;
  }
}

async function addDataIdToUser(username: string, dataId: string): Promise<void> {
  if (dataId === '') {
    console.error(`Data ID is empty for user ${username}.`);
    return;
  }
  console.log('进来了addDataIdToUser');

  const dbPromise = openDB();
  await dbPromise
    .then(async (db) => {
      const transaction = db.transaction([storeName], 'readwrite');
      const store = transaction.objectStore(storeName);

      // 检查是否已有此 username 的记录
      const existingDataRequest = store.get(username);
      let data = await new Promise<any>((resolve, reject) => {
        existingDataRequest.onsuccess = () => resolve(existingDataRequest.result);
        existingDataRequest.onerror = () => reject(existingDataRequest.error);
      });

      if (data) {
        // 检查 dataIds 数组的长度
        if (data.dataIds.length >= 5000) {
          // 清空 dataIds 数组
          data.dataIds = [];
          localStorage.removeItem('data_list');
          console.log(`Data IDs cleared for user ${username} due to max items limit.`);
        }

        // 如果不存在，则追加 dataId
        if (!data.dataIds.includes(dataId)) {
          data.dataIds.push(dataId);
        } else {
          console.log(`Data ID ${dataId} already exists for user ${username}.`);
          return;
        }
      } else {
        // 如果不存在，则创建新记录
        data = { id: username, username, dataIds: [dataId] };
      }

      // 更新或插入数据
      const putRequest = store.put(data);
      await new Promise((resolve, reject) => {
        putRequest.onsuccess = resolve;
        putRequest.onerror = () => reject(putRequest.error);
      });
    })
    .catch((error) => {
      console.error(`Failed to add dataId to user ${username}:`, error);
    });
}

async function getDataIdsForUser(username: string): Promise<string[]> {
  const dbPromise = openDB();
  return dbPromise
    .then(async (db) => {
      const transaction = db.transaction([storeName], 'readonly');
      const store = transaction.objectStore(storeName);
      const request = store.get(username);

      return new Promise<string[]>((resolve, reject) => {
        request.onsuccess = () => {
          const result = request.result;
          if (result) {
            resolve(result.dataIds);
          } else {
            resolve([]);
          }
        };
        request.onerror = () => reject(request.error);
      });
    })
    .catch((error) => {
      console.error(`Failed to get dataIds for user ${username}:`, error);
      return [];
    });
}

export const manageApi = new ManageApi(config);
export const sampleApi = new SampleApi(config);

export type UseStateType = <S>(initialState?: S | (() => S)) => [S, Dispatch<SetStateAction<S>>];
export type UseEffectType = (effect: EffectCallback, deps?: DependencyList | undefined) => void;
export const getRandomColor = () => {
  const rgb = [];
  for (let i = 0; i < 3; ++i) {
    let color = Math.floor(Math.random() * 256).toString(16);
    color = color.length == 1 ? '0' + color : color;
    rgb.push(color);
  }
  return '#' + rgb.join('');
};

export const createInfo = {
  classification: {
    name: 'Classification',
    avatar: './pics/classification.jpg',
    id: 1,
    labelFormats: { single_class: 'Single Class', multi_class: 'Multi Class' },
  },
  detection: {
    name: 'Detection',
    avatar: './pics/object_detection.jpg',
    id: 2,
    labelFormats: { coco: 'COCO', voc: 'VOC', yolo: 'YOLO' },
  },
  semanticSegmentation: {
    name: 'Semantic Segmentation',
    avatar: './pics/semantic_segmentation.jpg',
    id: 3,
    labelFormats: { mask: 'Mask', coco: 'Coco' },
  },
  instanceSegmentation: {
    name: 'Instance Segmentation',
    avatar: './pics/instance_segmentation.jpg',
    id: 4,
    labelFormats: { mask: 'Mask', coco: 'Coco' },
  },
  // keypointDetection: {
  //   name: 'Keypoint Detection',
  //   avatar: './pics/keypoint_detection.jpg',
  //   id: 5,
  // },

  // opticalCharacterRecognition: {
  //   name: 'OCR',
  //   avatar: './pics/keypoint_detection.jpg',
  //   id: 7,
  // },
};



/* helper functions */
export async function getVersion() {
  try {
    const version = await manageApi.getVersion();
    console.log('version', version.result);
    return version.result;
  } catch (err) {
    console.log('err', err);
    message.error(
      'Backend unavaliable, please make sure backend is running and check ur internet connection.',
    );
    return false;
  }
}

export const toDict = (arr: any[]) => {
  if (arr == undefined) return [];
  return JSON.parse(JSON.stringify(arr));
};

export function snake2camel(name: string) {
  if (!name) return name;
  return name
    .toLowerCase()
    .replace(/([-_][a-z])/g, (group) => group.toUpperCase().replace('-', '').replace('_', ''));
}

export function camel2snake(name: string) {
  // localstorage_list.splice(0, localstorage_list.length);
  if (!name) return name;
  return name.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
}

/*
if item is
- number, return idx where arr[idx].key == item
- object, return idx where arr[idx].key == item.key
*/
export const indexOf = (item: any, arr: any[], key: string) => {
  if (!key) return undefined;
  const toFind = typeof item == 'number' ? item : item[key];
  for (let idx = 0; idx < arr.length; idx++) {
    if (toFind == arr[idx][key]) return idx;
  }
  return undefined;
};

export function IntlInit(page: string) {
  const useintl = useIntl();
  return (id: string, pageName: string = page) => {
    if (id == '') return useintl.formatMessage({ id: pageName });
    return useintl.formatMessage({ id: pageName + '.' + id });
  };
}

// scale image
export const ScaleUtils = (useState: UseStateType, range: number[] = [0.1, 10]) => {
  const [curr, setCurr] = useState<number>(1);
  const [Scales, setScales] = useState<number[]>([]);
  const intl = IntlInit('pages.toolBar.scale');

  function setScale(scale: number) {
    let s: number = scale;
    if (s < range[0]) {
      s = range[0];
      message.error(intl('smallestScale') + ': ' + range[0]);
    }
    if (s > range[1]) {
      s = range[1];
      message.error(intl('largestScale') + ': ' + range[1]);
    }
    setCurr(s);
  }

  function change(delta: number) {
    setScale(curr + delta);
  }
  return { curr, change, setScale, setCurr, Scales, setScales };
};

export function ToolUtils(
  useState: UseStateType,
  { defaultTool }: { defaultTool: ToolType },
): {
  curr: ToolType;
  setCurr: (tool: ToolType) => void;
} {
  const [curr, setCurrRaw] = useState<ToolType>(defaultTool);
  const setCurr = (tool: ToolType) => {
    setCurrRaw(tool);
    console.trace();
  };
  return {
    curr,
    setCurr,
  };
}

export function LoadingUtils(useState: UseStateType) {
  const [curr, setCurr] = useState<boolean>(false);
  return { curr, setCurr };
}

export const ProjectUtils = (useState: UseStateType) => {
  const [all, setAll] = useState<Project[]>();
  const [curr, setCurr] = useState<Project>();
  const [finished, setFinished] = useState<number>();
  const splitIntl = IntlInitJsx('component.PPSplitDatasetModal');

  async function splitDataset(props: {
    train: number;
    val: number;
    test: number;
    project_id: number;
  }) {
    return projectApi
      .splitDataset(props.project_id, {
        train: props.train,
        val: props.val,
        test: props.test,
      })
      .then((res) => {
        message.success(splitIntl('success'));
      })
      .catch((err) => {
        message.error(splitIntl('fail'));
        serviceUtils.parseError(err, message);
      });
  }

  async function getAll(page_num: number | 1, page_size: number | 10) {
    try {
      const projects: Project[] = await projectApi.getAll(page_num, page_size);
      setAll(projects.result);
      return projects.result;
    } catch (err) {
      console.log('project getAll err', err);
      serviceUtils.parseError(err, message);
      return;
    }
  }

  async function getCurr(projectId: number) {
    if (projectId == undefined) return undefined;
    const project: Project = await projectApi.get(projectId);
    console.log('project_detail', project.data_list);
    localStorage.setItem('data_list', JSON.stringify(project.data_list));
    setCurr(project);
    return project;
  }

  async function getGroup(projectId: number) {
    if (projectId == undefined) return undefined;
    const project: Project = await projectApi.groupGet(projectId);
    setCurr(project);
    return project;
  }

  async function remove(project: Project | number | string) {
    const projectId: number = typeof project == 'object' ? project.projectId : +project;
    await projectApi.remove(projectId);
    getAll();
  }

  async function create(project: Project) {
    const newProject: Project = await projectApi.create(project);
    console.log('project:', project);
    console.log('request', newProject);
    return newProject;
  }

  async function update(projectId: number, project: Project) {
    const res = await projectApi.update(projectId, project);
    console.log('update res', res);
    return res;
  }

  async function predict(projectId: number, settings: object) {
    projectApi.predict(projectId, settings).catch((err) => {
      console.log('project predict err', err);
      serviceUtils.parseError(err, message);
    });
  }
  function setAllPredicted(predicted: boolean, projectId: string) {
    projectApi.setAll(projectId, { dataPredicted: predicted });
  }
  return {
    all,
    getAll,
    curr,
    getCurr,
    getGroup,
    remove,
    create,
    update,
    finished,
    predict,
    setAllPredicted,
    splitDataset,
  };
};

type labelUtilProps = {
  oneHot?: boolean;
  postSelect?: (label?: Label, activeIds?: Set<number>) => void;
  preUnsetCurr?: () => void;
};
export const LabelUtils = (
  useState: UseStateType,
  { oneHot = true, postSelect, preUnsetCurr }: labelUtilProps,
) => {
  const intlJsx = IntlInitJsx('component.label');

  const [all, setAll] = useState<Label[]>();
  const [curr, setCurrRaw] = useState<Label | undefined>();
  const [activeIds, setActiveIds] = useState(new Set<number>());
  const [isOneHot, setOneHot] = useState<boolean>(oneHot);

  async function getAll(projectId: number): Promise<Label[] | undefined> {
    if (projectId == undefined) return;
    try {
      const labels: Label[] = await projectApi.getLabels(projectId);
      setAll(labels);
      return labels;
    } catch (err) {
      console.log('label getall err ', err);
      serviceUtils.parseError(err, message);
      return;
    }
  }

  function onSelect(label: Label) {
    console.log('on select', isOneHot, label, activeIds, activeIds.has(label.labelId));
    let activeIdsTemp = activeIds;
    if (activeIds.has(label.labelId)) {
      activeIds.delete(label.labelId);
      setActiveIds(new Set(activeIds));
      activeIdsTemp = activeIds;
      if (curr?.labelId == label.labelId) unsetCurr();
    } else {
      activeIdsTemp = setCurr(label);
    }
    if (postSelect) postSelect(label, activeIdsTemp);
  }

  function unsetCurr() {
    activeIds.delete(curr?.labelId);
    setActiveIds(new Set(activeIds));
    if (preUnsetCurr) preUnsetCurr();
    setCurrRaw(undefined);
    return activeIds;
  }

  function setCurr(label: Label) {
    console.log('label setcurr', label);
    if (label == undefined) return unsetCurr();
    setCurrRaw(label);
    if (isOneHot) activeIds.clear();
    activeIds.add(label.labelId);
    setActiveIds(new Set(activeIds));
    return activeIds;
  }

  function initActive(annotations: Annotation[]) {
    activeIds.clear();
    for (const ann of annotations) activeIds.add(ann.labelId);
    setActiveIds(new Set(activeIds));
    if (isOneHot && activeIds.size > 1) message.error(intlJsx('ontHotMultiple'));
    console.log('initActive', activeIds);
  }

  async function create(label: Label | Label[]): Promise<Label[] | undefined> {
    console.log('createlabel', label);
    try {
      // debugger;
      const newLabels = await labelApi.create(
        label instanceof Array ? label : [label],
        undefined,
        true,
      );
      console.log('newLabels', newLabels);
      getAll(label instanceof Array ? label[0].projectId : label.projectId);
      return newLabels;
    } catch (err) {
      console.log('label create err', err);
      serviceUtils.parseError(err, message);
      return;
    }
  }

  async function remove(label: Label): Promise<Label[]> {
    console.log('to delete', label);
    try {
      await labelApi.remove(label.labelId);
      if (activeIds.has(label.labelId)) {
        activeIds.delete(label.labelId);
        setActiveIds(activeIds);
      }
      if (curr != undefined && curr.labelId == label.labelId) unsetCurr();
      const labels = await getAll(label.projectId);
      message.success(intlJsx('deleteSuccess'));
      return labels;
    } catch (err) {
      // console.log('label remove err', err);
      serviceUtils.parseError(err, message);
      return [];
    }
  }
  function isActive(label: Label) {
    return activeIds.has(label.labelId);
  }

  return {
    all,
    getAll,
    activeIds,
    setActiveIds,
    initActive,
    onSelect,
    curr,
    setCurr,
    isActive,
    create,
    remove,
    isOneHot,
    setOneHot,
  };
};
export const TaskUtils = (useState: UseStateType, props: { annotation: any; push: boolean }) => {
  const [all, setAll] = useState<Task[]>();
  const [currIdx, setCurrIdx] = useState<number>();
  const intl = IntlInitJsx('pages.toolBar.task');

  const turnTo = async (turnToIdx: number, change: string) => {
    console.log('turnToIdx', turnToIdx);
    if (change == 'prev') {
      currIdx_origin = turnToIdx + 1;
    } else {
      currIdx_origin = turnToIdx - 1;
    }
    setCurrIdx(turnToIdx);
    return true;
  };

  const getAll = async (
    projectId: number,
    page_num?: number | 1,
    page_size?: number | 10,
    turnToIdx?: number,
    orderBy: string = 'modified asc',
    taskAll: number = 0,
  ) => {
    try {
      if (page_num == undefined) {
        page_num = 1;
      }
      if (page_size == undefined) {
        page_size = 10;
      }
      const allRes = await projectApi.getTasks(projectId, page_num, page_size, orderBy, taskAll);
      console.log('rol', allRes);
      const task_data = allRes.data;
      setAll(allRes);
      if (turnToIdx != undefined) {
        turnTo(turnToIdx);
        return [task_data, task_data[turnToIdx]];
      }
      return allRes;
    } catch (err) {
      console.log('task getall err ', err);
      return serviceUtils.parseError(err, message);
    }
  };
  const getAll_2 = async (
    projectId: number,
    page_num?: number | 1,
    page_size?: number | 10,
    turnToIdx?: number,
    orderBy: string = 'modified asc',
    taskAll: number = 0,
  ) => {
    try {
      if (page_num == undefined) {
        page_num = 1;
      }
      if (page_size == undefined) {
        page_size = 10;
      }
      const allRes = await projectApi.getTasks_2(projectId, page_num, page_size, orderBy, taskAll);
      console.log('rol', allRes);
      const task_data = allRes.data;
      setAll(allRes);
      if (turnToIdx != undefined) {
        turnTo(turnToIdx);
        return [task_data, task_data[turnToIdx]];
      }
      return allRes;
    } catch (err) {
      console.log('task getall err ', err);
      return serviceUtils.parseError(err, message);
    }
  };

  function finished(progress: number = undefined) {
    if (progress == undefined) return 0;
    if (!all) return 0;
    return Math.round((all.length * progress) / 100);
  }
  const nextTask = (task: number) => {
    console.log('currIdx_next', currIdx);
    return turnTo(currIdx + 1, 'next');
  };
  const prevTask = () => {
    return turnTo(currIdx - 1, 'prev');
  };

  return {
    currIdx,
    all,
    setAll,
    turnTo,
    getAll,
    getAll_2,
    nextTask,
    prevTask,
    finished,
    get curr() {
      if (currIdx == undefined || all == undefined) return undefined;
      return all[0];
    },
  };
};

export function AnnotationUtils(
  useState: UseStateType,
  {
    label = undefined,
    project = undefined,
    recordHistory = () => {},
  }: { label: any; project: any; recordHistory: ({ annos: [] }) => void },
) {
  const [all, setAllRaw] = useState<Annotation[]>();
  const [curr, setCurrRaw] = useState<Annotation | undefined>();
  const tbIntl = IntlInitJsx('pages.toolBar');

  function setAll(annos: Annotation[]) {
    setAllRaw(annos);
  }
  const getImage = async (dataId: number, sault?: string) => {};

  const getAll = async (dataId: number) => {
    console.log('AnnotationUtils getAll, dataId:', dataId);
    if (dataId == undefined) return [];
    try {
      const annRes: Annotation[] = await dataApi.getAnnotations(dataId);
      console.log('All_annotations', annRes);
      setAll(annRes);
      return annRes;
    } catch (err) {
      console.log('AnnotationUtils ann getAll err', err);
      serviceUtils.parseError(err, message);
      return [];
    }
  };

  async function clear() {
    if (all.length == 0) return;
    await pushToBackend(all[0].dataId, []);
    setAllRaw([]);
    if (label) {
      label.setActiveIds(new Set());
    }
  }

  const create = async (
    annotation: Annotation | Annotation[],
    requestId?: string,
    deduplicate?: boolean,
  ) => {
    console.log('annotation', annotation);
    const prepAnn = (anno: Annotation) => {
      const ann = { ...anno };
      if (ann.label) ann.labelId = ann.label.labelId;
      ann.label = undefined;
      return ann;
    };
    try {
      const anns = annotation instanceof Array ? annotation.map(prepAnn) : [prepAnn(annotation)];
      console.log('anns', anns);
      console.log('deduplicate', deduplicate);
      if (deduplicate) {
        await annotationApi.create(anns, null, deduplicate);
      } else {
        await annotationApi.create(anns);
      }
      let annRes: Annotation[] = [];
      if (anns[0]?.dataId) annRes = await getAll(anns[0]?.dataId);
    } catch (err) {
      console.log('annotation create err', err);
      return serviceUtils.parseError(err, message);
    }
  };

  async function remove(annotation: number | Annotation) {
    const annId = typeof annotation == 'number' ? annotation : annotation.annotationId;
    if (annId == undefined) return;
    try {
      await annotationApi.remove(annId);
      if (all && all.length && all[0].dataId!) {
        const anns = await getAll(all[0].dataId);
        recordHistory({ annos: anns });
        console.log('anns', anns);
      }
      message.success(tbIntl('saveSuccess'));
    } catch (err) {
      console.log('annotation remove err', err);
      return serviceUtils.parseError(err, message);
    }
  }

  async function setCurr(annotation: Annotation | undefined) {
    console.log('annotation.setCurr:', annotation);
    if (annotation == undefined) {
      setCurrRaw(undefined);
      return;
    }
    setCurrRaw(annotation);
    label.setCurr(annotation.label);
  }

  async function update(annotation: Annotation) {
    if (!annotation.annotationId) return [];
    const ann = { ...annotation };
    ann.taskId = undefined;
    ann.label = undefined;
    ann.labelId = undefined;

    annotationApi
      .update(ann.annotationId, ann)
      .then((res) => {
        console.log('annotation update res', res);
        return getAll(ann.dataId);
      })
      .catch((err) => {
        console.log('annotation update err ', err);
        serviceUtils.parseError(err, message);
        return [];
      });
  }

  async function modify(annotation: Annotation) {
    if (!annotation) return undefined;
    if (annotation.annotationId == undefined) await create(annotation);
    else await update(annotation);
  }

  async function pushToBackend(dataId?: number, anns?: Annotation[]) {
    if (dataId == undefined || dataId == null) return;
    const newAll = anns ? anns : all;
    console.log('pushToBackend, dataId:', dataId, 'newAll:', newAll);
    try {
      const res = await dataApi.setAnnotations(dataId + '', newAll);
      console.log('res', res);
      setAllRaw(res);
      message.success(tbIntl('saveSuccess'));
      return res;
    } catch (err) {
      return serviceUtils.parseError(err, message);
    }
  }

  return {
    all,
    clear,
    getAll,
    create,
    remove,
    setCurr,
    update,
    modify,
    curr,
    setAll,
    pushToBackend,
  };
}

export const DataUtils = (useState: UseStateType) => {
  const [currIdx, setCurrIdx] = useState<number>();
  const [all, setAll] = useState<Data[]>([]);

  const turnTo = async (turnToIdx: number) => {
    setCurrIdx(turnToIdx);
  };
  //最后一次更改了getAll方法 10-21日
  // const getAll = async (projectId: number, dataId: number, turnToIdx: number | undefined) => {
  //   try {
  //     console.log('getAll_dataId', dataId);
  //     const allRes = await taskApi.getDatas(projectId, dataId);
  //     console.log('如果为空', allRes);
  //     // localStorage.setItem('allRes', allRes);
  //     // if (allRes = null) {
  //     //   allRes = localStorage.getItem('allRes');
  //     // }
  //     localStorage.setItem('conform', allRes[0].conform);
  //     setAll(allRes);
  //     console.log('allRes', allRes);
  //     parsedList = JSON.parse(localStorageListString);
  //     console.log('parsedList', parsedList);
  //     const numericList: number[] = parsedList.map((item) => parseInt(item, 10));
  //     if (allRes[0] && allRes[0].dataId !== undefined && !numericList.includes(allRes[0].dataId)) {
  //       numericList.push(allRes[0].dataId);
  //     }
  //     console.log('parsedList', numericList);
  //     numericList.forEach((dataId) => {
  //       addDataIdToUser(STORAGE_KEY, dataId);
  //     });
  //     // console.log('allRes[0].dataId', allRes);
  //     if (turnToIdx != undefined) {
  //       turnTo(turnToIdx);
  //       return [allRes, allRes[turnToIdx]];
  //     }
  //     return allRes;
  //   } catch (err) {
  //     return serviceUtils.parseError(err, message);
  //   }
  // };
  // getAll方法修改前，10-25日
  const getAll = async (projectId: number, dataId: number, turnToIdx: number | undefined) => {
    try {
      const allRes = await taskApi.getDatas(projectId, dataId);

      if (!Array.isArray(allRes) || allRes.length === 0) {
        console.error('allRes is not an array or is empty:', allRes);
        return []; // 返回空数组或适当的默认值
      }

      localStorage.setItem('conform', allRes[0].conform);
      setAll(allRes);
      try {
        parsedList = JSON.parse(localStorageListString);
      } catch (parseErr) {
        console.error('Error parsing localStorageListString:', parseErr);
        parsedList = null;
      }
      let numericList: number[];
      if (parsedList == null) {
        numericList = [];
      } else {
        numericList = parsedList.map((item) => parseInt(item, 10));
      }

      if (allRes[0] && allRes[0].dataId !== undefined && !numericList.includes(allRes[0].dataId)) {
        numericList.push(allRes[0].dataId);
      }
      if (numericList.length === 2000) {
        numericList.length = 0;
        console.log('numericList cleared due to max items limit.');
      }
      console.log('parsedList', numericList);
      numericList.forEach((dataId) => {
        addDataIdToUser(STORAGE_KEY, dataId);
      });

      if (turnToIdx != undefined) {
        if (turnToIdx < 0 || turnToIdx >= allRes.length) {
          console.error('turnToIdx is out of bounds:', turnToIdx);
          return [allRes, undefined]; // 返回一个包含 allRes 和 undefined 的数组
        }
        turnTo(turnToIdx);
        return [allRes, allRes[turnToIdx]];
      }

      return allRes;
    } catch (err) {
      return serviceUtils.parseError(err, message);
    }
  };

  const getAll_2 = async (projectId: number) => {
    console.log('进入getAll_2');
    console.log('DataId', projectId);
    if (projectId == undefined) return;
    console.log('进入getAll_2');
    try {
      const allRes = await taskApi.getDatas_2(projectId);
      console.log('getAll_2_allRes', allRes);
      setAll(allRes);
      console.log('allRes[0].dataId', allRes[0]);
      return allRes;
    } catch (err) {
      console.log('error123456', err);
      return serviceUtils.parseError(err, message);
    }
  };
  const updatePredicted = async (dataId: string, flag: boolean) => {
    try {
      await dataApi.update(dataId, {
        // predicted: false,
        predicted: flag,
      });
      // debugger;
    } catch (err) {
      console.log('data getall err ', err);
      return serviceUtils.parseError(err, message);
    }
  };
  const setAnnotations = async (dataId: number, annotations: Annotation[]) => {
    try {
      await dataApi.setAnnotations(dataId + '', annotations);
    } catch (err) {
      console.log('data getall err ', err);
      return serviceUtils.parseError(err, message);
    }
  };

  return {
    all,
    getAll,
    getAll_2,
    turnTo,
    setAnnotations,
    updatePredicted,
    get curr() {
      console.log('data.getcurr', currIdx, all);
      if (currIdx == undefined || all == undefined) return undefined;
      return all[currIdx];
    },

    get imgSrc() {
      console.log('imgSrc', all);
      if (all && all[currIdx]) {
        return `${baseUrl}/datas/${all[currIdx].dataId}/image?sault=${all[currIdx].sault}`;
      }
      return ``;
    },
  };
};

export function exportDataset(
  projectId: number,
  exportDir: string,
  exportFormat: string,
  segMaskType: string,
  finalValues: boolean,
) {
  console.log('finalValues', finalValues);
  return projectApi
    .exportDataset(projectId, finalValues, {
      exportDir: exportDir,
      exportFormat: exportFormat,
      segMaskType: segMaskType,
    })
    .then((res) => {
      if (res.status !== 200) {
        message.error(res.message);
        throw new Error(res.message || 'Export failed with status ' + res.status);
      }
    })
    .catch((err) => {
      console.log('export error', err);
      serviceUtils.parseError(err, message);
      throw err;
    });
}

export function updataProject(projectId: number, path: string) {
  return projectApi
    .updata_project(projectId, path)
    .then((res) => {
      console.log('updata_test_2', res);
      if (res.status !== 200) {
        message.error(res.message);
        throw new Error(res.message || 'Export failed with status ' + res.status);
      }
      return res; //确保返回结果
    })
    .catch((err) => {
      console.log('export error', err);
      serviceUtils.parseError(err, message);
      throw err;
    });
}
export async function conformData(dataId: number | undefined, status: string | number) {
  const response = await projectApi.conform(dataId, status);

  // setRefreshVar((prev) => prev + 1);
  return response;
}


export function importDataset(
  projectId: number,
  importDir: string,
  importFormat: string | undefined,
) {
  return projectApi
    .importDataset(projectId, { importDir: importDir, importFormat: importFormat })
    .then((res) => {
      message.success('额外数据导入成功');
      console.log(res);
    })
    .catch((err) => {
      serviceUtils.parseError(err, message);
      throw new Error();
    });
}
export function PageInit(
  useState: UseStateType,
  useEffect: UseEffectType,
  props: {
    effectTrigger?: {
      postTaskChange?: (labels?: Label[], annotations?: Annotation[]) => void;
      postProjectChanged?: () => void;
    };
    label: labelUtilProps;
    tool: { defaultTool: ToolType };
    annotation?: Annotation;
    task: { push: boolean };
    // recordHistory?: ({ annos: [] }) => void;
  },
) {
  message.config({ maxCount: 6, duration: 2 });
  const tool = ToolUtils(useState, props.tool ? props.tool : {});
  const loading = LoadingUtils(useState);
  const scale = ScaleUtils(useState);
  const data = DataUtils(useState);
  const project = ProjectUtils(useState);
  const label = LabelUtils(useState, props.label ? props.label : {});
  const annHistory = HistoryUtils(useState, rpcApi);
  const annotation = AnnotationUtils(useState, {
    ...props.annotation,
    label: label,
    project: project,
    recordHistory: annHistory.record,
  });

  const task = TaskUtils(useState, { annotation, ...props.task });
  // 更新 data 和 annotation 的函数

  const [refreshVar, setRefreshVar] = useState<number>(0);

  function refresh() {
    for (const t of [100, 200, 1000, 2000])
      setTimeout(function () {
        setRefreshVar(Math.random());
      }, t);
  }

  useEffect(() => {
    // onload, get project, label, task info
    const projectIdStr = serviceUtils.getQueryVariable('projectId');
    if (projectIdStr == undefined) {
      // history.push('/');
      return;
    }
    const projectId = parseInt(projectIdStr);
    project.getCurr(projectId).catch((err) => {
      serviceUtils.parseError(err, message);
      // history.push('/');
      return;
    });
    loading.setCurr(true);
    label.getAll(projectId);

    const orderBy = localStorage.getItem('orderBy');
    // if (orderBy) task.getAll(projectId, undefined, undefined, undefined, orderBy, 1);
    // else task.getAll(projectId, undefined, undefined, undefined, undefined, 1);
    task.getAll(projectId, undefined, undefined, undefined, orderBy, 1);

    localStorage.removeItem('orderBy');
    // project.getFinished(projectId);
  }, []);

  useEffect(() => {
    if (!project.curr) return;
    console.log('project.curr', project.curr);
    if (props.effectTrigger?.postProjectChanged) {
      props.effectTrigger.postProjectChanged();
    }
  }, [project.curr]);

  useEffect(() => {
    // when all task is set, set current task
    if (task.all) {
      if (task.all.length == 0) {
        message.error('No task under this project, please import data first!');
        history.push(`/project_overview?projectId=${project.curr?.project_id}`);
        return;
      }
      const currTaskId = localStorage.getItem('currTaskId');
      if (currTaskId != null) {
        for (let idx = 0; idx < task.all.length; idx++) {
          if (task.all[idx].task_id == currTaskId) {
            task.turnTo(idx);
            break;
          }
        }
        localStorage.removeItem('currTaskId');
      } else {
        task.turnTo(0);
      }
    }
  }, [task.all]);
  useEffect(() => {
    // when current task is set, get task's data, data's annotation
    console.log('task.currIdx', task.currIdx);
    console.log('进来了_useEffect', task);
    const onTaskChange_3 = async () => {
      console.log('进入onTaskChange_3');
      const [allData, currData] = await data.getAll(
        localStorage.getItem('projectId'),
        localStorage.getItem('currDataId'),
        0,
      );
      const allAnns = await annotation.getAll(currData.dataId);
      if (label.all) for (const lab of label.all) lab.active = false;
      if (props.effectTrigger?.postTaskChange)
        props.effectTrigger?.postTaskChange(label.all, allAnns);
      annotation.setAll(allAnns);
      loading.setCurr(false);
      refresh();
    };

    const onTaskChange = async () => {
      console.log('进入onTaskChange');
      console.log('task.curr', task.curr);
      localStorage.removeItem('index_prev');
      if (task.curr?.project_id) {
        console.log('哈哈哈哈');
        const [allData, currData] = await data.getAll(
          task.curr.project_id,
          localStorage.getItem('currDataId'),
          0,
        );

        const allAnns = await annotation.getAll(currData.dataId);
        if (label.all) for (const lab of label.all) lab.active = false;
        if (props.effectTrigger?.postTaskChange)
          props.effectTrigger?.postTaskChange(label.all, allAnns);
        annotation.setAll(allAnns);
      }
      loading.setCurr(false);
      refresh();
    };

    // const onTaskChange = async () => {
    //   console.log('进入onTaskChange');
    //   console.log('task.curr', task.curr);
    //   localStorage.removeItem('index_prev');

    //   if (task.curr?.project_id) {
    //     console.log('哈哈哈哈');
    //     try {
    //       const result = await data.getAll(
    //         task.curr.project_id,
    //         localStorage.getItem('currDataId'),
    //         0,
    //       );

    //       if (Array.isArray(result) && result.length === 2) {
    //         const [allData, currData] = result;

    //         const allAnns = await annotation.getAll(currData.dataId);
    //         if (label.all) for (const lab of label.all) lab.active = false;
    //         if (props.effectTrigger?.postTaskChange)
    //           props.effectTrigger?.postTaskChange(label.all, allAnns);
    //         annotation.setAll(allAnns);
    //       } else {
    //         console.error('data.getAll returned an unexpected result:', result);
    //       }
    //     } catch (error) {
    //       console.error('Error in data.getAll:', error);
    //     }
    //   }

    //   loading.setCurr(false);
    //   refresh();
    // };
    const onTaskChange_prev = async () => {
      console.log('task.currIdx', task.currIdx);
      // const cachedTaskIdxString = localStorage.getItem(STORAGE_KEY);
      getDataIdsForUser(STORAGE_KEY)
        .then(async (dataIds) => {
          console.log(`Data IDs for ${STORAGE_KEY}:`, dataIds);
          let index_prev = localStorage.getItem('index_prev')
            ? localStorage.index_prev
            : dataIds.length - 1;
          console.log('index_prev_1', index_prev);
          if (dataIds.length && dataIds.length > 0) {
            index_prev = index_prev - 1 > 0 ? index_prev - 1 : 0;
            console.log('index_prev', index_prev);
            localStorage.setItem('index_prev', index_prev);
            const dataId = dataIds[index_prev];
            console.log('dataId_prev', dataId);
            const currData = await data.getAll_2(dataId);
            console.log('currData', currData[0]);
            const allAnns = await annotation.getAll(currData[0].dataId);
            if (label.all) {
              for (const lab of label.all) {
                lab.active = false;
              }
            }
            if (props.effectTrigger?.postTaskChange) {
              props.effectTrigger.postTaskChange(label.all, allAnns);
            }
            annotation.setAll(allAnns);
            loading.setCurr(false);
            refresh();
          } else {
            console.log('No valid cached task index found.');
          }
        })
        .catch((error) => {
          console.error('Error fetching data IDs:', error);
        });
    };

    loading.setCurr(true);
    // 获取 projectId
    const projectIdStr = localStorage.getItem('projectId');
    const projectId_2 = projectIdStr ? parseInt(projectIdStr, 10) : null;
    if (task.currIdx < currIdx_origin) {
      onTaskChange_prev();
    } else if (task.currIdx == undefined && projectId_2) {
      onTaskChange_3();
    } else {
      onTaskChange();
    }
  }, [task.currIdx]);

  useEffect(() => {
    refresh();
  }, [annotation.all, label.all]);

  // useEffect(() => {
  //   if (data.curr && data.curr.conform) {
  //     console.log('data.curr.conform changed:', data.curr.conform);
  //     // 执行刷新逻辑
  //     refresh();
  //   }
  // }, [data.curr]);

  return { tool, loading, scale, annotation, task, data, project, label, refreshVar, annHistory };
}

// ml related
export function ModelUtils(useState: UseStateType, mlBackendUrl: string = undefined) {
  const [curr, setCurr] = useState<Model>();
  const [all, setAll] = useState<Model[]>();
  const [backendUrl, setBackendUrl] = useState<string>(mlBackendUrl);
  const [loading, setLoading] = useState<boolean>(false);
  const intl = IntlInit('component.PPInteractorModal');
  // let modelApi = new ModelApi(new Configuration({ basePath: backendUrl }));
  let modelApi = new ModelApi(new Configuration({ basePath: backendUrl }));

  async function getAll() {
    try {
      const models: Model[] = await modelApi.getAll();
      console.log('models', models);
      setAll(models);
      return models;
    } catch (err) {
      serviceUtils.parseError(
        err,
        message,
        'The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.',
      );
      return;
    }
  }

  async function setMlBackendUrl(url: string) {
    modelApi = new ModelApi(new Configuration({ basePath: url }));
    setBackendUrl(url);
    console.log('ml backend url set', url);
  }

  async function train(modelName: string, dataDir: string, configs: object) {
    try {
      checkAPI();
      return await modelApi.train(modelName, { dataDir: dataDir, configs: configs });
    } catch (err) {
      return serviceUtils.parseError(err, message);
    }
  }

  async function predict(model: string, data: InlineObject1) {
    try {
      checkAPI();
      return await modelApi.predict(model, data);
    } catch (err) {
      return serviceUtils.parseError(err, message);
    }
  }

  async function load(modelName: string, modelPath?: string, paramPath?: string) {
    try {
      await checkAPI();
      setLoading(true);
      await modelApi.load(modelName, {
        initParams: { model_path: modelPath, param_path: paramPath },
      });
      setLoading(false);
    } catch (err) {
      setLoading(false);
      message.error(intl('loadFail'));
      throw err;
    }
  }

  async function checkAPI() {
    console.log('model api url', modelApi.configuration.configuration.basePath);
    if (!modelApi.configuration.configuration.basePath) {
      // debugger;
      throw new Error('Set ML backend url first!');
    }
    return (await modelApi.isBackendUp()).trim();
  }

  return {
    setMlBackendUrl,
    curr,
    all,
    getAll,
    setCurr,
    modelApi,
    train,
    predict,
    load,
    loading,
    setLoading,
    checkAPI,
    backendUrl,
  };
}
